﻿/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Credits
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// This component has been devigned by Jose Luis Latorre (www.silverlightguy.com), from Brainsiders (www.brainsiders.com)
// Thanks to:
// Cigdem Patlak, Edu Couchez & Sandra Saenz for his 
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// There have been some techniques used that have learned and applied or adpated as follows:
//
// - For the circular animation I have used the smart technique conceived by John Bruin - http://www.johnbruin.net/index.php/category/silverlight/ - Thanks John!
// - Note: At the end I took out the code for adding text as Edu Couchez kindly provided a xaml with the encircled text in a way better typography than I could get using code.
//   Thanks Edu!.
// - For the physics engine and 3D interaction, I have used the physics engine from the BouncingPlane Demo, showed by Scott Guthrie during the Keynote at MIX09, 
//   I think that the original author of it is Henry hahn - http://blogs.msdn.com/henryh/archive/2009/03/20/mix09-the-gratuitous-graphics-demo.aspx  - Thanks Henry!!
// - Thanks to Cigdem Patlak and Sandra Saenz for his recommendations in colors typography and design in general.
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;

namespace SUGWSK_Logo
{
    public partial class Logo : UserControl
    {
        public Logo()
        {
            InitializeComponent();

            InitAnimationLogo();
            InitCircularText();
            Init3DInteraction();
        }

        #region Logo Test "toggle" and Animation System
        private string ActualAnimationRunning = ""; //None.
        private void InitAnimationLogo() {

            Uri u = new Uri("silverlightLogoLoop.wmv", UriKind.Relative);
            this.silverlightLogoLoop_wmv.Source = u;
            ActualAnimationRunning = "silverlightLogoLoop_wmv";
            this.silverlightLogoLoop_wmv.MediaEnded += new RoutedEventHandler(silverlightLogoLoop_wmv_MediaEnded);
            this.silverlightLogoLoop_wmv.AutoPlay = true;
            this.silverlightLogoLoop_wmv.IsMuted = true;
            this.silverlightLogoLoop_wmv.Play();
        }


        void silverlightLogoLoop_wmv_MediaEnded(object sender, RoutedEventArgs e)
        {
            if (ActualAnimationRunning == "silverlightLogoLoop_wmv")
            {
                this.silverlightLogoLoop_wmv.Stop();
                this.silverlightLogoLoop_wmv.Play();
            }
            else
            {
                //do the cleaning... ;)
                this.silverlightLogoLoop_wmv.MediaEnded -= silverlightLogoLoop_wmv_MediaEnded;
            }
        }
        #endregion Logo Test "toggle" and Animation System


        #region Circulo animado exterior al logo
        string strText = "-   SUGWSK   -   Silverlight User Group Website Starter Kit   ";
        const double PI = 3.14159265;
        Canvas c;
        double scale = 1.0;
        Random rnd = new Random();
        public void InitCircularText() {
            c = this.OuterCircleOverlay;
//            c.Background = null;
            c.RenderTransformOrigin = new Point(.5, .5);
            TransformGroup tg = new TransformGroup();
            RotateTransform rt = new RotateTransform();
            rt.Angle = 0;
            ScaleTransform st = new ScaleTransform();
            st.ScaleX = scale;
            st.ScaleY = scale;
            tg.Children.Add(rt);
            tg.Children.Add(st);
            c.RenderTransform = tg;
            int dir = 0;
            while (dir == 0)
            {
                dir = rnd.Next(-3, 3);
            }
            Storyboard s = RS(c, 360 * dir);
            s.RepeatBehavior = RepeatBehavior.Forever;
            s.Begin();

            //mmm....
            scale = scale * 1.20;            
        }
        Storyboard RS(DependencyObject o, int angle)
        {
            Storyboard s = new Storyboard();
            DoubleAnimationUsingKeyFrames a1 = GA(o, "(UIElement.RenderTransform).(TransformGroup.Children)[0].(RotateTransform.Angle)", angle, 20);
            s.Children.Add(a1);
            return s;
        }
        DoubleAnimationUsingKeyFrames GA(DependencyObject o, string p, double e, double s)
        {
            DoubleAnimationUsingKeyFrames a = new DoubleAnimationUsingKeyFrames();
            a.BeginTime = TimeSpan.FromSeconds(0);
            Storyboard.SetTarget(a, o);
            Storyboard.SetTargetProperty(a, new PropertyPath(p, new object[0]));
            SplineDoubleKeyFrame sp = new SplineDoubleKeyFrame();
            sp.KeyTime = TimeSpan.FromSeconds(s);
            sp.Value = e;
            a.KeyFrames.Add(sp);
            return a;
        }
        private void Draw()
        {
            double x, y;
            double r = 175; //Radius
            double dFontSize = 24;
            double cx = c.Width / 2;
            double cy = c.Height / 2;
            //strText; = tbText.Text;
            //while (strText.Length > 0 && strText.Length < 360)
            //{
            //    strText = strText + strText;
            //}

            //if (strText.Length > 0)
            //    strText = strText.Substring(0, 360);

            int cc = 0;
            //for (int w = 1; w < COUNT; w++)
            //{
                double pastAngle = 0;
                Double AngleDiff = 0;
                c.Children.Clear();
                int j = 0;
                int maxLength = 360; // strText.Length;
                int stepDegrees = 6;
                //for (int i = 0; i < 360; i = i + 7)

                for (int i = 0; i < maxLength; i = i + stepDegrees)
                {
                    if ( j >= strText.Length)
                    {
                        break;
                    }

                    //double angle = (2 * PI / 360) * (i + w * 45);
                    double angle = (2 * PI / 360) * (i + 1 * 45);
                    x = cx + r * Math.Sin(angle);
                    y = cy - r * Math.Cos(angle);

                    TextBlock tb = new TextBlock();
                    if (strText.Length > 0)
                        tb.Text = strText.Substring(j, 1);
                    tb.FontFamily = new FontFamily("Arial Black");
                    tb.FontSize = dFontSize;
                    tb.Width = tb.ActualWidth;
                    tb.Height = tb.ActualHeight;
                    tb.Foreground = new SolidColorBrush(Colors.Blue);

                    tb.SetValue(Canvas.LeftProperty, -tb.Width / 2);
                    tb.SetValue(Canvas.TopProperty, -tb.Height / 2);
                    tb.RenderTransformOrigin = new Point(0.5, 0.5);
                    TransformGroup tg = new TransformGroup();
                    RotateTransform rt = new RotateTransform();
                    //rt.Angle = i + w * 45;
                    
                    rt.Angle = i + 1 * 45;
                    AngleDiff = rt.Angle - pastAngle;
                    pastAngle = rt.Angle;
                    tg.Children.Add(rt);

                    TranslateTransform tt = new TranslateTransform();
                    tt.X = x;
                    tt.Y = y;
                    tg.Children.Add(tt);

                    tb.RenderTransform = tg;

                    c.Children.Add(tb);

                    j++;
                }
                cc++;
                if (cc > 4)
                    cc = 0;

            //}
        }
        private void UserControl_Loaded(object sender, RoutedEventArgs e)
        {
           // Draw();
        }

        #endregion Circulo animado exterior al logo



        #region 3D Interaction with moving words
        long FirstClickTime;

        private void Init3DInteraction() {
            FirstClickTime = DateTime.Now.Ticks;
            Storyboard sb = new Storyboard();
            DoubleAnimation da = new DoubleAnimation();
            da.From = -3.0;
            da.To = 3.0;
            da.Duration = new Duration(TimeSpan.FromMilliseconds(1000));
            da.AutoReverse = true;
            da.RepeatBehavior = RepeatBehavior.Forever;

            c3DInteraction.RenderTransform = new TranslateTransform();
            Storyboard.SetTarget(da, c3DInteraction.RenderTransform);
            Storyboard.SetTargetProperty(da, new PropertyPath("Y"));
            sb.Children.Add(da);
            sb.Begin();        
        }
        private void OuterCircleOverlay_MouseLeftButtonDown(object sender, MouseButtonEventArgs args)
        {
            if (((UIElement)args.OriginalSource) == null)
                return;

            //Get click position relative to the clicked object
            Point p = args.GetPosition((UIElement)args.OriginalSource);

            //Determine simple moment arm and direction against clicked object on both x & y axes.
            double DirectionalScalarY = (p.Y - (c3DInteraction.RenderSize.Height / 2)) / (c3DInteraction.RenderSize.Height / 2);
            double DirectionalScalarX = ((c3DInteraction.RenderSize.Width / 2) - p.X) / (c3DInteraction.RenderSize.Width / 2);


            //Apply only if on the top 10% of the clickable frame.
            if (DirectionalScalarY < -.90)
            {
                //Simulated double-click.  Each tick is .1 ms.
                //Setting double-click definition as two clicks
                //within 250 ms.
                if (DateTime.Now.Ticks - FirstClickTime < 10000 * 250)
                    FlipFrame(DirectionalScalarX);

                FirstClickTime = DateTime.Now.Ticks;
                return;
            }


            Storyboard sb = new Storyboard();
            //            c3DInteraction.Projection = new PlaneProjection();

            DoubleAnimationUsingKeyFrames da = BuildKeyFrames(1.0, 80.0, 1.0, 35.0, DirectionalScalarX, 5.0);
            Storyboard.SetTarget(da, c3DInteraction.Projection);
            Storyboard.SetTargetProperty(da, new PropertyPath("RotationY"));
            sb.Children.Add(da);

            da = BuildKeyFrames(1.0, 80.0, 1.0, 35.0, DirectionalScalarY, 5.0);
            Storyboard.SetTarget(da, c3DInteraction.Projection);
            Storyboard.SetTargetProperty(da, new PropertyPath("RotationX"));
            sb.Children.Add(da);

            sb.Begin();

        }
        public void FlipFrame(double DirectionalScalarX)
        {
            Storyboard sb = new Storyboard();
            DoubleAnimation da1 = new DoubleAnimation();
            da1.From = -5.0;
            da1.To = -355.0;
            da1.Duration = new Duration(TimeSpan.FromMilliseconds(550.0));
            SineEase se = new SineEase();
            se.EasingMode = EasingMode.EaseInOut;
            da1.EasingFunction = se;

            Storyboard.SetTarget(da1, c3DInteraction.Projection);
            Storyboard.SetTargetProperty(da1, new PropertyPath("RotationX"));

            DoubleAnimationUsingKeyFrames da2 = BuildKeyFrames(1.0, 80.0, 1.0, 35.0, DirectionalScalarX, 5.0);
            Storyboard.SetTarget(da2, c3DInteraction.Projection);
            Storyboard.SetTargetProperty(da2, new PropertyPath("RotationY"));

            sb.Children.Add(da1);
            sb.Children.Add(da2);
            sb.Begin();
        }
        //My own hacked up physics model.
        DoubleAnimationUsingKeyFrames BuildKeyFrames(double Mass, double SpringConstant, double Dampening, double ForceMultiplier, double DirectionalScalar, double offset)
        {
            int sample = 75; //in ms
            int duration = 10000; //in ms

            //declare physics constants
            double lamda = Dampening / (2 * Math.Sqrt(SpringConstant * Mass));
            double omega_not = Math.Sqrt(SpringConstant / Mass);
            double omega_d = omega_not * Math.Sqrt(1.0 - Math.Pow(lamda, 2.0));
            double amplitude = DirectionalScalar * ForceMultiplier;

            DoubleAnimationUsingKeyFrames double_animation = new DoubleAnimationUsingKeyFrames();
            LinearDoubleKeyFrame frame;

            for (int i = 0; i < (duration / sample); i++)
            {
                frame = new LinearDoubleKeyFrame();
                frame.KeyTime = KeyTime.FromTimeSpan(TimeSpan.FromMilliseconds(i * sample));
                frame.Value = offset + amplitude * Math.Exp(-1 * lamda * omega_not * (double)sample * i / 1000) * Math.Sin(omega_d * i * sample / 1000);
                double_animation.KeyFrames.Add(frame);
            }

            return double_animation;
        }
        //For some of the effects, apply to where the mouse is.
        private void OuterCircleOverlay_MouseMove(object sender, MouseEventArgs args)
        {
            Point p = new Point();
            p.X = args.GetPosition(c3DInteraction).X / (c3DInteraction.RenderSize.Width);
            p.Y = args.GetPosition(c3DInteraction).Y / (c3DInteraction.RenderSize.Height);
        }
        #endregion 3D Interaction with moving words

    }
}
